home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / gchess40.lha / gnuchess4.0p62 / src / book.c < prev    next >
C/C++ Source or Header  |  1993-06-22  |  32KB  |  1,326 lines

  1. /*
  2.  * book.c - C source for GNU CHESS
  3.  *
  4.  * Copyright (c) 1988,1989,1990 John Stanback Copyright (c) 1992 Free Software
  5.  * Foundation
  6.  *
  7.  * This file is part of GNU CHESS.
  8.  *
  9.  * GNU Chess is free software; you can redistribute it and/or modify it under
  10.  * the terms of the GNU General Public License as published by the Free
  11.  * Software Foundation; either version 2, or (at your option) any later
  12.  * version.
  13.  *
  14.  * GNU Chess is distributed in the hope that it will be useful, but WITHOUT ANY
  15.  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  16.  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
  17.  * details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License along with
  20.  * GNU Chess; see the file COPYING.  If not, write to the Free Software
  21.  * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  22.  */
  23. #include "gnuchess.h"
  24. #include "ataks.h"
  25. #include <unistd.h>
  26.  
  27. #ifdef GENIT
  28. FILE *GEN;
  29. #endif
  30. #ifdef GENIT
  31. FILE *GEN;
  32. #endif
  33. #ifdef MSDOS
  34. #include <io.h>
  35. #endif
  36. #ifndef MSDOS
  37. #define O_BINARY 0
  38. #endif
  39. #include <fcntl.h>
  40. unsigned booksize = BOOKSIZE;
  41. unsigned int BKTBLSIZE;
  42. unsigned long BOOKMASK;
  43. unsigned bookcount = 0;
  44. unsigned bookpocket = BOOKPOCKET;
  45. static struct bookentry
  46. {
  47.     unsigned long bookkey;
  48.     unsigned long bookbd;
  49.     unsigned short bmove;
  50.     unsigned short hint;
  51.     unsigned short count;
  52.     unsigned short flags;
  53. } *OBEND;
  54. struct bookentry *OpenBook = NULL;
  55. static struct bookentry **BookTable;
  56.  
  57. unsigned short bookmaxply = BOOKMAXPLY;
  58.  
  59. char *bookfile = NULL;
  60. char *binbookfile = BINBOOK;
  61.  
  62. int GotBook = false;
  63. static char bmvstr[4][6];
  64. unsigned long bhashbd, bhashkey;
  65.  
  66.  
  67. void
  68. Balgbr (short int f, short int t, short int flag)
  69.  
  70.  
  71.      /*
  72.       * Generate move strings in different formats.
  73.       */
  74.  
  75. {
  76.     int m3p;
  77.     bmvstr[0][0] = bmvstr[1][0] = bmvstr[2][0] = bmvstr[3][0] = '\0';
  78.  
  79.     if (f != t)
  80.       {
  81.       /* algebraic notation */
  82.       bmvstr[0][0] = cxx[column (f)];
  83.       bmvstr[0][1] = rxx[row (f)];
  84.       bmvstr[0][2] = cxx[column (t)];
  85.       bmvstr[0][3] = rxx[row (t)];
  86.       bmvstr[0][4] = bmvstr[3][0] = '\0';
  87.       if (((bmvstr[1][0] = pxx[board[f]]) == 'P') || (flag & promote))
  88.         {
  89.         if (bmvstr[0][0] == bmvstr[0][2])    /* pawn did not eat */
  90.           {
  91.               bmvstr[2][0] = bmvstr[1][0] = bmvstr[0][2];    /* to column */
  92.               bmvstr[2][1] = bmvstr[1][1] = bmvstr[0][3];    /* to row */
  93.               m3p = 2;
  94.           }
  95.         else
  96.             /* pawn ate */
  97.           {
  98.               bmvstr[2][0] = bmvstr[1][0] = bmvstr[0][0];    /* column */
  99.               bmvstr[2][1] = bmvstr[1][1] = bmvstr[0][2];    /* to column */
  100.               bmvstr[2][2] = bmvstr[0][3];
  101.               m3p = 3;    /* to row */
  102.           }
  103.         if (flag & promote)
  104.           {
  105.               bmvstr[0][4] = bmvstr[1][2] = bmvstr[2][m3p] = qxx[flag & pmask];
  106.               bmvstr[0][5] = bmvstr[1][3] = bmvstr[2][m3p + 1] = bmvstr[3][0] = '\0';
  107.           }
  108.         else
  109.             bmvstr[2][m3p] = bmvstr[1][2] = '\0';
  110.         }
  111.       else
  112.           /* not a pawn */
  113.         {
  114.         bmvstr[2][0] = bmvstr[1][0];
  115.         bmvstr[2][1] = bmvstr[0][1];
  116.         bmvstr[2][2] = bmvstr[1][1] = bmvstr[0][2];    /* to column */
  117.         bmvstr[2][3] = bmvstr[1][2] = bmvstr[0][3];    /* to row */
  118.         bmvstr[2][4] = bmvstr[1][3] = '\0';
  119.         strcpy (bmvstr[3], bmvstr[2]);
  120.         bmvstr[3][1] = bmvstr[0][0];
  121.         if (flag & cstlmask)
  122.           {
  123.               if (t > f)
  124.             {
  125.                 strcpy (bmvstr[1], bmvstr[0]);
  126.                 strcpy (bmvstr[0], CP[5]);
  127.                 strcpy (bmvstr[2], CP[7]);
  128.             }
  129.               else
  130.             {
  131.                 strcpy (bmvstr[1], bmvstr[0]);
  132.                 strcpy (bmvstr[0], CP[6]);
  133.                 strcpy (bmvstr[2], CP[8]);
  134.             }
  135.           }
  136.         }
  137.       }
  138.     else
  139.     bmvstr[0][0] = bmvstr[1][0] = bmvstr[2][0] = bmvstr[3][0] = '\0';
  140. }
  141.  
  142. #ifndef QUIETBOOKGEN
  143. void
  144. bkdisplay (s, cnt, moveno)
  145.      char *s;
  146.      int cnt;
  147.      int moveno;
  148. {
  149.     static short pnt;
  150.     struct leaf *node;
  151.     int r, c, l;
  152.  
  153.     pnt = TrPnt[2];
  154.     printf ("matches = %d\n", cnt);
  155.     printf ("inout move is :%s:move number %d side %s\n", s, moveno / 2 + 1, (moveno & 1) ? "white" : "black");
  156. #ifndef SEMIQUIETBOOKGEN
  157.     printf ("legal moves are \n");
  158.     while (pnt < TrPnt[3])
  159.       {
  160.       node = &Tree[pnt++];
  161.       Balgbr (node->f, node->t, (short) node->flags);
  162.       printf ("%s %s %s %s\n", bmvstr[0], bmvstr[1], bmvstr[2], bmvstr[3]);
  163.       }
  164.     printf ("\n current board is\n");
  165.     for (r = 7; r >= 0; r--)
  166.       {
  167.       for (c = 0; c <= 7; c++)
  168.         {
  169.         l = locn (r, c);
  170.         if (color[l] == neutral)
  171.             printf (" -");
  172.         else if (color[l] == white)
  173.             printf (" %c", qxx[board[l]]);
  174.         else
  175.             printf (" %c", pxx[board[l]]);
  176.         }
  177.       printf ("\n");
  178.       }
  179.     printf ("\n\n");
  180. #endif
  181. }
  182.  
  183. #endif
  184.  
  185. int
  186. BVerifyMove (char *s, short unsigned int *mv, int moveno)
  187.  
  188.      /*
  189.       * Compare the string 's' to the list of legal moves available for the
  190.       * opponent. If a match is found, make the move on the board.
  191.       */
  192.  
  193. {
  194.     static short pnt, tempb, tempc, tempsf, tempst, cnt;
  195.     static struct leaf xnode;
  196.     struct leaf *node;
  197.  
  198.     *mv = 0;
  199.     cnt = 0;
  200.     MoveList (opponent, 2);
  201.     pnt = TrPnt[2];
  202.     while (pnt < TrPnt[3])
  203.       {
  204.       node = &Tree[pnt++];
  205.       Balgbr (node->f, node->t, (short) node->flags);
  206.       if (strcmp (s, bmvstr[0]) == 0 || strcmp (s, bmvstr[1]) == 0 ||
  207.           strcmp (s, bmvstr[2]) == 0 || strcmp (s, bmvstr[3]) == 0)
  208.         {
  209.         cnt++;
  210.         xnode = *node;
  211.         }
  212.       }
  213.     if (cnt == 1)
  214.       {
  215.       MakeMove (opponent, &xnode, &tempb, &tempc, &tempsf, &tempst, &INCscore);
  216.       if (SqAtakd (PieceList[opponent][0], computer))
  217.         {
  218.         UnmakeMove (opponent, &xnode, &tempb, &tempc, &tempsf, &tempst);
  219.         /* Illegal move in check */
  220. #ifndef QUIETBOOKGEN
  221.         printf (CP[77]);
  222.         printf ("\n");
  223.         bkdisplay (s, cnt, moveno);
  224. #endif
  225.         return (false);
  226.         }
  227.       else
  228.         {
  229.         *mv = (xnode.f << 8) | xnode.t;
  230.         Balgbr (xnode.f, xnode.t, false);
  231.         return (true);
  232.         }
  233.       }
  234.     /* Illegal move */
  235. #ifndef QUIETBOOKGEN
  236.     printf (CP[75], s);
  237.     bkdisplay (s, cnt, moveno);
  238. #endif
  239.     return (false);
  240. }
  241.  
  242. void
  243. RESET (void)
  244.  
  245.      /*
  246.       * Reset the board and other variables to start a new game.
  247.       */
  248.  
  249. {
  250.     short int l;
  251.  
  252.     flag.illegal = flag.mate = flag.post = flag.quit = flag.reverse = flag.bothsides = flag.onemove = flag.force = false;
  253.     flag.material = flag.coords = flag.hash = flag.easy = flag.beep = flag.rcptr = true;
  254.     flag.stars = flag.shade = flag.back = flag.musttimeout = false;
  255. #ifdef CLIENT
  256.     flag.gamein = true;
  257. #else
  258.     flag.gamein = false;
  259. #endif
  260.     GenCnt = epsquare = 0;
  261.     GameCnt = 0;
  262.     Developed[white] = Developed[black] = false;
  263.     castld[white] = castld[black] = false;
  264.     PawnThreat[0] = CptrFlag[0] = false;
  265.     opponent = white;
  266.     computer = black;
  267.     for (l = 0; l < 64; l++)
  268.       {
  269.       board[l] = Stboard[l];
  270.       color[l] = Stcolor[l];
  271.       Mvboard[l] = 0;
  272.       }
  273.     InitializeStats ();
  274.     hashbd = hashkey = 0;
  275. }
  276.  
  277. int
  278. Vparse (FILE * fd, unsigned short *mv, short int side, char *opening, int moveno)
  279. {
  280.     register int c, i;
  281.     char s[128];
  282.     char *p;
  283.  
  284.     while (true)
  285.       {
  286.  
  287.       while ((c = getc (fd)) == ' ' || c == '\n');
  288.       if (c == '\r')
  289.           continue;
  290.       i = 0;
  291.       if (c == '!')
  292.         {            /* comment */
  293.         p = opening;
  294.         do
  295.           {
  296.               *p++ = c;
  297.               c = getc (fd);
  298.               if (c == '\r')
  299.               continue;
  300.               /* goes to end of line */
  301.               if (c == '\n')
  302.             {
  303.                 *p = '\0';
  304. #ifdef GENIT
  305. fprintf(GEN,"\n%s\n",opening);
  306. #endif
  307.                 return 0;
  308.               } if (c == EOF)
  309.               return -1;
  310.           }
  311.         while (true);
  312.         }
  313.       /* is it a move number or analysis ( in [ ] ) */
  314.       /* number cannot start with a 0 because of 0-0 */
  315.       else if (!isalpha (c) && c != '0')
  316.         {
  317.         int nonspace = false;
  318.  
  319.         /* analysis */
  320.         if (c == '[')
  321.           {
  322.               /* scan to ] */
  323.               while ((c = getc (fd)) != ']')
  324.             {
  325.                 if (c == EOF)
  326.                 return -1;
  327.             } continue;
  328.           }
  329.         while (true)
  330.           {
  331.               c = getc (fd);
  332.               if (c == '\r')
  333.               continue;
  334.               if (c == '\n')
  335.               return 0;
  336.               if (c == EOF)
  337.             {
  338.                 return -1;
  339.             }
  340.               /* stop at first nonspace a ... is space */
  341.               /* must be nonspace because of 0-0 */
  342.               if (nonspace)
  343.             {
  344.                 if (c != '.' && c != ' ')
  345.                 break;
  346.             }
  347.               if (c == '.')
  348.             {
  349.                 nonspace = true;
  350.             }
  351.               /* stop if alpha must be move */
  352.               else if (isalpha (c))
  353.               break;
  354.           }
  355.         }
  356.       s[0] = (char) c;
  357.  
  358.       while ((c = getc (fd)) != '?' && c != '+' && c != ' ' && c != '\n' && c != '\t' && c != EOF)
  359.         {
  360.         if (c == '\r')
  361.             continue;
  362.         if (c != 'x')
  363.             s[++i] = c;
  364.         }
  365.       s[++i] = '\0';
  366.  
  367.       if (c == EOF)
  368.           return (-1);
  369.       if (s[0] == '!' || s[0] == ';')
  370.         {
  371.         while (c != '\n' && c != EOF)
  372.             c = getc (fd);
  373.         if (c == EOF)
  374.             return -1;
  375.         else
  376.             return (0);
  377.         }
  378.       if ((strcmp (s, "o-o-o") == 0) || (strcmp (s, "OOO") == 0) || (strcmp (s, "O-O-O") == 0) || (strcmp (s, "0-0-0") == 0))
  379.         {
  380.         if (side == black)
  381.             strcpy (s, "e8c8");
  382.         else
  383.             strcpy (s, "e1c1");
  384.         }
  385.       else if ((strcmp ("o-o", s) == 0) || (strcmp (s, "OO") == 0) || (strcmp (s, "O-O") == 0) || (strcmp (s, "0-0") == 0))
  386.         {
  387.         if (side == black)
  388.             strcpy (s, "e8g8");
  389.         else
  390.             strcpy (s, "e1g1");
  391.         }
  392.       else if (strcmp (s, "draw") == 0)
  393.           continue;
  394.       else if (strcmp (s, "1-0") == 0)
  395.           continue;
  396.       else if (strcmp (s, "0-1") == 0)
  397.           continue;
  398.       if (isupper (s[i - 1]))
  399.           s[i - 1] = tolower (s[i - 1]);
  400.  
  401.       bhashkey = hashkey;
  402.       bhashbd = hashbd;
  403. #ifdef GENIT
  404.     if(c == '?') fprintf(GEN,"%s? ",s); else fprintf(GEN,"%s ",s);
  405. #endif
  406.  
  407.       i = BVerifyMove (s, mv, i);
  408.       if (c == '?')
  409.         {            /* Bad move, not for the program to play */
  410.         *mv |= BADMOVE;    /* Flag it ! */
  411.         c = getc (fd);
  412.         }
  413.       else if (c == '+' || c == '\r')
  414.           c = getc (fd);
  415.       if (!i)
  416.         {
  417.         printf ("%s \n", opening);
  418.         /* flush to start of next */
  419.         while ((c = getc (fd)) != '!' && c != EOF);
  420.         if (c == EOF)
  421.             return -1;
  422.         else
  423.           {
  424.               ungetc (c, fd);
  425.               return i;
  426.           }
  427.         }
  428.       return (i);
  429.       }
  430. }
  431.  
  432. #if defined GDX
  433. struct gdxadmin
  434. {
  435.     unsigned int bookcount;
  436.     unsigned int booksize;
  437.     unsigned long maxoffset;
  438. } ADMIN, B;
  439.  
  440. struct gdxdata
  441. {
  442.     unsigned long hashbd;
  443.     unsigned short hashkey;
  444.     unsigned short bmove;
  445.     unsigned short hint;
  446.     unsigned short count;
  447. } DATA;
  448.  
  449. #ifdef LONG64
  450. #define lts(x) (((x>>48)&0xfffe)|side)
  451. #else
  452. #define lts(x) (((x>>16)&0xfffe)|side)
  453. #endif
  454. unsigned long currentoffset;
  455. int gfd;
  456.  
  457. void
  458. GetOpenings (void)
  459.  
  460.      /*
  461.       * Read in the Opening Book file and parse the algebraic notation for a move
  462.       * into an unsigned integer format indicating the from and to square. Create
  463.       * a linked list of opening lines of play, with entry->next pointing to the
  464.       * next line and entry->move pointing to a chunk of memory containing the
  465.       * moves. More Opening lines of up to 100 half moves may be added to
  466.       * gnuchess.book. But now its a hashed table by position which yields a move
  467.       * or moves for each position. It no longer knows about openings per say only
  468.       * positions and recommended moves in those positions.
  469.       */
  470. {
  471.     register short int i;
  472.     char opening[256];
  473.     char msg[256];
  474.     int mustwrite = false;
  475.     unsigned short xside, doit, side;
  476.     short int c;
  477.     unsigned short mv;
  478.     unsigned short ix;
  479.     unsigned int x;
  480.     unsigned int games = 0;
  481.  
  482.     FILE *fd;
  483. #ifdef GENIT
  484.     if ((GEN = fopen ("GEN", "w")) == NULL) { printf("GEN FAIL\n");exit(1);}
  485. #endif
  486.     if ((fd = fopen (bookfile, "r")) == NULL)
  487.     fd = fopen ("gnuchess.book", "r");
  488.     if (fd != NULL)
  489.       {
  490.       /* yes add to book */
  491.       /* open book as writer */
  492.       gfd = open (binbookfile, O_RDONLY | O_BINARY);
  493.       if (gfd >= 0)
  494.         {
  495.         if (sizeof(struct gdxadmin) == read (gfd, &ADMIN, sizeof (struct gdxadmin)))
  496.           {
  497.               B.bookcount = ADMIN.bookcount;
  498.               B.booksize = ADMIN.booksize;
  499.               B.maxoffset = ADMIN.maxoffset;
  500.               if (B.booksize && !(B.maxoffset == ((unsigned long)(B.booksize - 1) * sizeof (struct gdxdata) + sizeof (struct gdxadmin))))
  501.             {
  502.                 printf ("bad format %s\n", binbookfile);
  503.                 exit (1);
  504.             }
  505.           }
  506.         else
  507.           {
  508.               printf ("bad format %s\n", binbookfile);
  509.               exit (1);
  510.           }
  511.         close (gfd);
  512.                 gfd = open (binbookfile, O_RDWR | O_BINARY);
  513.  
  514.         }
  515.       else
  516.         {
  517.                 gfd = open (binbookfile, O_RDWR | O_CREAT | O_BINARY, 0644);
  518.         ADMIN.bookcount = B.bookcount = 0;
  519.         ADMIN.booksize = B.booksize = booksize;
  520.                 B.maxoffset = ADMIN.maxoffset = (unsigned long) (booksize - 1) * sizeof (struct gdxdata) + sizeof (struct gdxadmin);
  521.         DATA.hashbd = 0;
  522.         DATA.hashkey = 0;
  523.         DATA.bmove = 0;
  524.         DATA.hint = 0;
  525.         DATA.count = 0;
  526.         write (gfd, &ADMIN, sizeof (struct gdxadmin));
  527.         printf ("creating bookfile %s  %ld %d\n", binbookfile, B.maxoffset, B.booksize);
  528.         for (x = 0; x < B.booksize; x++)
  529.           {
  530.               write (gfd, &DATA, sizeof (struct gdxdata));
  531.           }
  532.  
  533.  
  534.         }
  535.       if (gfd >= 0)
  536.         {
  537.  
  538.  
  539.         /* setvbuf(fd,buffr,_IOFBF,2048); */
  540.         side = white;
  541.         xside = black;
  542.         hashbd = hashkey = 0;
  543.         i = 0;
  544.  
  545.         while ((c = Vparse (fd, &mv, side, opening, i)) >= 0)
  546.           {
  547.               if (c == 1)
  548.                         {
  549.  
  550.                 /*
  551.                              * if not first move of an opening and first
  552.                              * time we have seen it save next move as
  553.                              * hint
  554.                              */
  555.                 i++;
  556.                 if (i < bookmaxply + 2)
  557.                   {
  558.                   if (i > 1)
  559.                     {
  560.                     DATA.hint = mv & 0x3f3f;
  561.                     }
  562.                   if (i < bookmaxply + 1)
  563.                     {
  564.                     doit = true;
  565.  
  566.                     /*
  567.                                  * see if this position and
  568.                                  * move already exist from
  569.                                  * some other opening
  570.                                  */
  571.  
  572.                     /*
  573.                                  * is this ethical, to offer
  574.                                  * the bad move as a
  575.                                  * hint?????
  576.                                  */
  577.                     ix = 0;
  578.                     if (mustwrite)
  579.                       {
  580.                           lseek (gfd, currentoffset, SEEK_SET);
  581.                           write (gfd, &DATA, sizeof (struct gdxdata));
  582.                           mustwrite = false;
  583.                       }
  584.                     doit = true;
  585.                                         currentoffset = (unsigned long) (bhashkey % B.booksize) * sizeof (struct gdxdata) + sizeof (struct gdxadmin);
  586.                     while (true)
  587.                       {
  588.  
  589.                           lseek (gfd, currentoffset, SEEK_SET);
  590.                           if ((read (gfd, &DATA, sizeof (struct gdxdata)) == 0))
  591.                             break;
  592.  
  593.                           if (DATA.bmove == 0) break;
  594.                           if (DATA.hashkey == (unsigned short)(lts(bhashkey)) && DATA.hashbd == bhashbd)
  595.                         {
  596.                             if ((DATA.bmove & (~(LASTMOVE | BADMOVE))) == (mv & ~BADMOVE))
  597.                               {
  598.                               DATA.count++;
  599.                               if(mv & BADMOVE) DATA.bmove |= BADMOVE;
  600.                                                           /*
  601.                                            * yes so just bump count - count is
  602.                                            * used to choose opening move in
  603.                                            * proportion to its presence in the book
  604.                                            */
  605.                               doit = false;
  606.                               mustwrite = true;
  607.                               break;
  608.                               } else if(DATA.bmove & LASTMOVE){
  609.                             DATA.bmove &= (~LASTMOVE);    
  610.                                   lseek (gfd, currentoffset, SEEK_SET);
  611.                                   write (gfd, &DATA, sizeof (struct gdxdata));
  612.                             }
  613.                         }
  614.                           currentoffset += sizeof (struct gdxdata);
  615.                           if (currentoffset > B.maxoffset)
  616.                           currentoffset = sizeof (struct gdxadmin);
  617.                       }
  618.  
  619.                     /*
  620.                                  * doesn`t exist so add it to
  621.                                  * the book
  622.                                  */
  623.                     if (!mustwrite)
  624.                       {
  625.                           B.bookcount++;
  626. #if !defined CHESSTOOL && !defined XBOARD
  627.                           if (B.bookcount % 1000 == 0)
  628.                           printf ("%d rec %d openings processed\n", B.bookcount,games);
  629. #endif
  630.                           /* initialize a record */
  631.                           DATA.hashbd = bhashbd;
  632.                           DATA.hashkey = (unsigned short)(lts(bhashkey));
  633.                           DATA.bmove = mv | LASTMOVE;
  634.                           DATA.count = 1;
  635.                           DATA.hint = 0;
  636.                           mustwrite = true;
  637.                       }
  638.                     }
  639.                   }
  640.                 computer = opponent;
  641.                 opponent = computer ^ 1;
  642.  
  643.                 xside = side;
  644.                 side = side ^ 1;
  645.             }
  646.               else if (i > 0)
  647.             {
  648.                 /* reset for next opening */
  649.                 games++;
  650.                 if (mustwrite)
  651.                   {
  652.                   lseek (gfd, currentoffset, SEEK_SET);
  653.                   write (gfd, &DATA, sizeof (struct gdxdata));
  654.                   mustwrite = false;
  655.                   }
  656.                 RESET ();
  657.                 i = 0;
  658.                 side = white;
  659.                 xside = black;
  660.                 hashbd = hashkey = 0;
  661.  
  662.             }
  663.           }
  664.         if (mustwrite)
  665.           {
  666.               lseek (gfd, currentoffset, SEEK_SET);
  667.               write (gfd, &DATA, sizeof (struct gdxdata));
  668.               mustwrite = false;
  669.           }
  670.         fclose (fd);
  671.         /* write admin rec with counts */
  672.         ADMIN.bookcount = B.bookcount;
  673.         currentoffset = 0;
  674.         lseek (gfd, currentoffset, SEEK_SET);
  675.         write (gfd, &ADMIN, sizeof (struct gdxadmin));
  676.  
  677.         close (gfd);
  678.         }
  679.       }
  680.     if (binbookfile != NULL)
  681.       {
  682.       /* open book as writer */
  683.       gfd = open (binbookfile, O_RDONLY | O_BINARY);
  684.       if (gfd >= 0)
  685.         {
  686.         read (gfd, &ADMIN, sizeof (struct gdxadmin));
  687.         B.bookcount = ADMIN.bookcount;
  688.         B.booksize = ADMIN.booksize;
  689.         B.maxoffset = ADMIN.maxoffset;
  690.                 if (B.booksize && !(B.maxoffset == ((unsigned long) (B.booksize - 1) * sizeof (struct gdxdata) + sizeof (struct gdxadmin))))
  691.           {
  692.               printf ("bad format %s\n", binbookfile);
  693.               exit (1);
  694.           }
  695.  
  696.         }
  697.       else
  698.         {
  699.         B.bookcount = 0;
  700.         B.booksize = booksize;
  701.  
  702.         }
  703.  
  704. #if !defined CHESSTOOL && !defined XBOARD
  705.       sprintf (msg, CP[213], B.bookcount, B.booksize);
  706.       ShowMessage (msg);
  707. #endif
  708.       }
  709.     /* set every thing back to start game */
  710.     Book = BOOKFAIL;
  711.     RESET ();
  712.     /* now get ready to play */
  713.     if (!B.bookcount)
  714.       {
  715. #if !defined CHESSTOOL && !defined XBOARD
  716.       ShowMessage (CP[212]);
  717. #endif
  718.       Book = 0;
  719.       }
  720. }
  721.  
  722.  
  723. int
  724. OpeningBook (unsigned short *hint, short int side)
  725.  
  726.      /*
  727.       * Go thru each of the opening lines of play and check for a match with the
  728.       * current game listing. If a match occurs, generate a random number. If this
  729.       * number is the largest generated so far then the next move in this line
  730.       * becomes the current "candidate". After all lines are checked, the
  731.       * candidate move is put at the top of the Tree[] array and will be played by
  732.       * the program. Note that the program does not handle book transpositions.
  733.       */
  734.  
  735. {
  736.     unsigned short r, m;
  737.     int possibles = TrPnt[2] - TrPnt[1];
  738.  
  739.     gsrand ((unsigned int) time ((long *) 0));
  740.     m = 0;
  741.  
  742.     /*
  743.      * find all the moves for this position  - count them and get their
  744.      * total count
  745.      */
  746.     {
  747.     register unsigned short i, x;
  748.     register unsigned short rec = 0;
  749.     register unsigned short summ = 0;
  750.     register unsigned short h = 0, b = 0;
  751.     struct gdxdata OBB[128];
  752.     if (B.bookcount == 0)
  753.       {
  754.           Book--;
  755.           return false;
  756.       }
  757.         currentoffset = (unsigned long) (hashkey % B.booksize) * sizeof (struct gdxdata) + sizeof (struct gdxadmin);
  758.     x = 0;
  759.     lseek (gfd, currentoffset, SEEK_SET);
  760.     while (true)
  761.       {
  762.           if (read (gfd, &OBB[x], sizeof (struct gdxdata)) == 0) break;
  763.           if (OBB[x].bmove == 0) break;
  764.  
  765.  
  766.           if (OBB[x].hashkey == (unsigned short)(lts(hashkey)) && OBB[x].hashbd == hashbd)
  767.         {
  768.             x++;if(OBB[x-1].bmove & LASTMOVE) break;
  769.         }
  770.         currentoffset += sizeof (struct gdxdata); 
  771.           if (currentoffset > B.maxoffset){
  772.           lseek (gfd, sizeof (struct gdxadmin), SEEK_SET);
  773.           currentoffset = sizeof (struct gdxadmin); 
  774.         }
  775.  
  776.       }
  777.     if (x == 0)
  778.       {
  779.           Book--;
  780.           return false;
  781.       }
  782. #ifdef DEBUG33
  783.     {
  784.     int loop = true;
  785.     while(loop){
  786.         loop = false;
  787.     for (i = 1; i < x; i++){
  788.     struct gdxdata tmp;
  789.     if(OBB[i].count > OBB[i-1].count){loop = true;tmp = OBB[i-1]; OBB[i-1]=OBB[i]; OBB[i]=tmp;}
  790.     }
  791.     }
  792.     }
  793.     for (i = 0; i < x; i++)
  794. {
  795. Balgbr((OBB[i].bmove>>8) & 0x3f,(OBB[i].bmove ) & 0x3f,0);
  796. printf(" %s ",bmvstr[0],OBB[i].count);
  797. Balgbr((OBB[i].hint>>8) & 0x3f,(OBB[i].hint ) & 0x3f,0);
  798. printf("%s %c %d\n",bmvstr[0],(OBB[i].bmove & BADMOVE)?'*':' ',OBB[i].count);
  799. }
  800. #endif
  801.     for (i = 0; i < x; i++)
  802.       {
  803.           if ((m = OBB[i].bmove) & BADMOVE)
  804.         {
  805.             m ^= BADMOVE;
  806.             /* is the move is in the MoveList */
  807.             for (b = TrPnt[1]; b < (unsigned) TrPnt[2]; b++)
  808.               {
  809.               if (((Tree[b].f << 8) | Tree[b].t) == m)
  810.                 {
  811.  
  812.                 if (--possibles)
  813.                     Tree[b].score = DONTUSE;
  814.                 break;
  815.                 }
  816.               }
  817.         }
  818.           else summ += OBB[i].count;
  819.       }
  820.     if (summ == 0)
  821.           {
  822.               Book--;
  823.               return false;
  824.           }
  825.  
  826.     r = (urand () % summ);
  827.     for (i = 0; i < x; i++)
  828.         if (!(OBB[i].bmove & BADMOVE) ){
  829.             if( r < OBB[i].count)
  830.                 {
  831.                 rec = i;
  832.                 break;
  833.                 }
  834.               else
  835.               r -= OBB[i].count;
  836.         } 
  837.  
  838.     h = ((OBB[rec].hint) & 0x3f3f);
  839.     m = ((OBB[rec].bmove) & 0x3f3f);
  840.     /* make sure the move is in the MoveList */
  841.     for (b = TrPnt[1]; b < (unsigned) TrPnt[2]; b++)
  842.       {
  843.           if (((Tree[b].f << 8) | Tree[b].t) == m)
  844.         {
  845.             Tree[b].flags |= book;
  846.             Tree[b].score = 0;
  847.             break;
  848.         }
  849.       }
  850.     /* Make sure its the best */
  851.  
  852.     pick (TrPnt[1], TrPnt[2] - 1);
  853.     if (Tree[TrPnt[1]].score)
  854.       {
  855.           /* no! */
  856.           Book--;
  857.           return false;
  858.       }
  859.     /* ok pick up the hint and go */
  860.     *hint = h;
  861.     return true;
  862.     }
  863.     Book--;
  864.     return false;
  865. }
  866.  
  867. #else
  868.  
  869.  
  870. static void
  871. bkalloc (unsigned bksize)
  872. {
  873.     register int i, f;
  874.     /* allocate space for the book */
  875.     f = (bksize + bookpocket - 1) / bookpocket;
  876.     bksize = booksize = f * bookpocket;
  877. #ifdef MSDOS
  878.     OpenBook = (struct bookentry *) _halloc (bksize , sizeof (struct bookentry));
  879. #else
  880.     OpenBook = (struct bookentry *) malloc (bksize * sizeof (struct bookentry));
  881. #endif
  882.     if (OpenBook == NULL)
  883.       {
  884.       perror ("memory alloc");
  885.       exit (1);
  886.       }
  887.     for (BKTBLSIZE = 1, BOOKMASK = 1; BKTBLSIZE < f; BKTBLSIZE *= 2, BOOKMASK = (BOOKMASK << 1));
  888.     BOOKMASK -= 1;
  889.     BookTable = (struct bookentry **) malloc (BKTBLSIZE * sizeof (struct bookentry *));
  890.     if (BookTable == NULL)
  891.       {
  892.       perror ("memory alloc");
  893.       exit (1);
  894.       }
  895.     for (i = 0; i < BKTBLSIZE; i++)
  896.       {
  897.       BookTable[i] = &OpenBook[bksize / BKTBLSIZE * i];
  898.       }
  899.     OBEND = (OpenBook + ((bksize) * sizeof (struct bookentry)));
  900. }
  901.  
  902. void
  903. GetOpenings (void)
  904.  
  905. /*
  906.  * Read in the Opening Book file and parse the algebraic notation for a move
  907.  * into an unsigned integer format indicating the from and to square. Create
  908.  * a linked list of opening lines of play, with entry->next pointing to the
  909.  * next line and entry->move pointing to a chunk of memory containing the
  910.  * moves. More Opening lines of up to 100 half moves may be added to
  911.  * gnuchess.book. But now its a hashed table by position which yields a move
  912.  * or moves for each position. It no longer knows about openings per say only
  913.  * positions and recommended moves in those positions.
  914.  */
  915. {
  916.     FILE *fd;
  917.     register struct bookentry *OB = NULL;
  918.     register struct bookentry *OC = NULL;
  919.     register short int i;
  920.     char opening[80];
  921.     char msg[80];
  922.     unsigned short xside, doit, side;
  923.     short int c;
  924.     unsigned short mv;
  925.  
  926.     if (binbookfile != NULL)
  927.       {
  928.       fd = fopen (binbookfile, "rb");
  929.       if (fd != NULL)
  930.         {
  931.         fscanf (fd, "%d\n", &booksize);
  932.         fscanf (fd, "%d\n", &bookcount);
  933.         fscanf (fd, "%d\n", &bookpocket);
  934.         bkalloc (booksize);
  935. #if !defined CHESSTOOL && !defined XBOARD
  936.         sprintf (msg, CP[213], bookcount, booksize);
  937.         ShowMessage (msg);
  938. #endif
  939.         if (0 > fread (OpenBook, sizeof (struct bookentry), booksize, fd))
  940.           {
  941.               perror ("fread");
  942.               exit (1);
  943.           }
  944.         /* set every thing back to start game */
  945.         Book = BOOKFAIL;
  946.         for (i = 0; i < 64; i++)
  947.           {
  948.               board[i] = Stboard[i];
  949.               color[i] = Stcolor[i];
  950.           }
  951.         fclose (fd);
  952.  
  953.         }
  954.       }
  955.     if ((fd = fopen (bookfile, "r")) == NULL)
  956.     fd = fopen ("gnuchess.book", "r");
  957.     if (fd != NULL)
  958.       {
  959.  
  960.       if (OpenBook == NULL)
  961.         {
  962.         bkalloc (booksize);
  963.         for (OB = OpenBook; OB < &OpenBook[booksize]; OB++)
  964.             OB->count = 0;
  965.         }
  966.       OC = NULL;
  967.       /* setvbuf(fd,buffr,_IOFBF,2048); */
  968.       side = white;
  969.       xside = black;
  970.       hashbd = hashkey = 0;
  971.       i = 0;
  972.  
  973.       while ((c = Vparse (fd, &mv, side, opening, i)) >= 0)
  974.         {
  975.         if (c == 1)
  976.           {
  977.  
  978.               /*
  979.                * if not first move of an opening and first
  980.                * time we have seen it save next move as
  981.                * hint
  982.                */
  983.               i++;
  984.               if (i < bookmaxply + 2)
  985.             {
  986.                 if (i > 1 && OB->count == 1)
  987.                 OB->hint = mv & 0x3f3f;
  988.                 OC = OB;    /* save for end marking */
  989.                 if (i < bookmaxply + 1)
  990.                   {
  991.                   doit = true;
  992.  
  993.                   /*
  994.                        * see if this position and
  995.                        * move already exist from
  996.                        * some other opening
  997.                        */
  998.  
  999.                   /*
  1000.                        * is this ethical, to offer
  1001.                        * the bad move as a
  1002.                        * hint?????
  1003.                        */
  1004.                   OB = BookTable[bhashkey & BOOKMASK];
  1005.                   while (OB->count)
  1006.                     {
  1007.                     if (OB->bookkey == bhashkey
  1008.                         && OB->bookbd == bhashbd
  1009.                         && (OB->flags & SIDEMASK) == side
  1010.                         && (OB->bmove & ~BADMOVE) == (mv & ~BADMOVE))
  1011.                       {
  1012.  
  1013.                           /*
  1014.                            * yes so * just bump * count - * count is * used to
  1015.                            * choose * opening * move in * proportion * to its
  1016.                            * presence * in the * book
  1017.                            */
  1018.                           doit = false;
  1019.                           OB->count++;
  1020.                           break;
  1021.                       }
  1022.  
  1023.                     /*
  1024.                          * Book is hashed
  1025.                          * into BKTBLSIZE
  1026.                          * chunks based on
  1027.                          * hashkey
  1028.                          */
  1029.                     if (++OB == OBEND)
  1030.                         OB = OpenBook;
  1031.                     }
  1032.  
  1033.                   /*
  1034.                        * doesn`t exist so add it to
  1035.                        * the book
  1036.                        */
  1037.                   if (doit)
  1038.                     {
  1039.                     bookcount++;
  1040.                     if (bookcount > (booksize - 2 * BKTBLSIZE))
  1041.                       {
  1042.                           printf ("booksize exceeded\n");
  1043.                                               exit (0);
  1044.                       }
  1045. #if !defined CHESSTOOL && !defined XBOARD
  1046.                     if (bookcount % 1000 == 0)
  1047.                         printf ("%d processed\n", bookcount);
  1048. #endif
  1049.                     OB->bookkey = bhashkey;
  1050.                     OB->bookbd = bhashbd;
  1051.                     OB->bmove = mv;
  1052.                     OB->hint = 0;
  1053.                     OB->count = 1;
  1054.                     OB->flags = side;
  1055.                     }
  1056.                   }
  1057.             }
  1058.               computer = opponent;
  1059.               opponent = computer ^ 1;
  1060.  
  1061.               xside = side;
  1062.               side = side ^ 1;
  1063.           }
  1064.         else if (i > 0)
  1065.           {
  1066.               /* reset for next opening */
  1067.               RESET ();
  1068.               i = 0;
  1069.               side = white;
  1070.               xside = black;
  1071.               hashbd = hashkey = 0;
  1072.  
  1073.           }
  1074.         }
  1075.       fclose (fd);
  1076.       if (binbookfile != NULL)
  1077.         {
  1078.         fd = fopen (binbookfile, "wb");
  1079.         if (fd != NULL)
  1080.           {
  1081.               fprintf (fd, "%d\n%d\n%d\n", booksize, bookcount, bookpocket);
  1082.               if (0 > fwrite (OpenBook, sizeof (struct bookentry), booksize, fd))
  1083.                 perror ("fwrite");
  1084.               fclose (fd);
  1085.               binbookfile = NULL;
  1086.           }
  1087.         }
  1088. #if !defined CHESSTOOL && !defined XBOARD
  1089.       sprintf (msg, CP[213], bookcount, booksize);
  1090.       ShowMessage (msg);
  1091. #endif
  1092.       /* set every thing back to start game */
  1093.       Book = BOOKFAIL;
  1094.       RESET ();
  1095.       }
  1096.     else if (OpenBook == NULL)
  1097.       {
  1098. #if !defined CHESSTOOL && !defined XBOARD
  1099.       if (!bookcount)
  1100.           ShowMessage (CP[212]);
  1101. #endif
  1102.       Book = 0;
  1103.       }
  1104. }
  1105.  
  1106.  
  1107. int
  1108. OpeningBook (unsigned short *hint, short int side)
  1109.  
  1110. /*
  1111.  * Go thru each of the opening lines of play and check for a match with the
  1112.  * current game listing. If a match occurs, generate a random number. If this
  1113.  * number is the largest generated so far then the next move in this line
  1114.  * becomes the current "candidate". After all lines are checked, the
  1115.  * candidate move is put at the top of the Tree[] array and will be played by
  1116.  * the program. Note that the program does not handle book transpositions.
  1117.  */
  1118.  
  1119. {
  1120.     short pnt;
  1121.     unsigned short m;
  1122.     unsigned r, cnt, tcnt, ccnt;
  1123.     register struct bookentry *OB, *OC;
  1124.     int possibles = TrPnt[2] - TrPnt[1];
  1125.  
  1126. #ifdef E4OPENING
  1127.     if ((computer == white && GameCnt == 0))
  1128.       {
  1129.       /* double check */
  1130.       int i;
  1131.       int go = true;
  1132.  
  1133.       for (i = 0; i < 64; i++)
  1134.         {
  1135.         if (!(board[i] == Stboard[i] && color[i] == Stcolor[i]))
  1136.           {
  1137.               go = false;
  1138.               break;
  1139.           }
  1140.         }
  1141.       if (go)
  1142.         {
  1143.         m = 0xc1c;
  1144.         /* make sure the move is in the MoveList */
  1145.         for (pnt = TrPnt[1]; pnt < TrPnt[2]; pnt++)
  1146.           {
  1147.               if (((Tree[pnt].f << 8) | Tree[pnt].t) == (short) m)
  1148.             {
  1149.                 Tree[pnt].flags |= book;
  1150.                 Tree[pnt].score = 0;
  1151.                 break;
  1152.             }
  1153.           }
  1154.         /* Make sure its the best */
  1155.  
  1156.         pick (TrPnt[1], TrPnt[2] - 1);
  1157.         if (!Tree[TrPnt[1]].score)
  1158.           {
  1159.               /* ok pick up the hint and go */
  1160.               *hint = 0x3424;
  1161.               return true;
  1162.           }
  1163.         }
  1164.       }
  1165.     else if ((computer == black && GameCnt == 1))
  1166.       {
  1167.       int go = true;
  1168.       int i;
  1169.       char bd[64], cl[64];
  1170.  
  1171.       for (i = 0; i < 64; i++)
  1172.         {
  1173.         bd[i] = Stboard[i];
  1174.         cl[i] = Stcolor[i];
  1175.         }
  1176.       bd[0x1c] = bd[0xc];
  1177.       bd[0xc] = no_piece;
  1178.       cl[0x1c] = white;
  1179.       cl[0xc] = neutral;
  1180.       for (i = 0; i < 64; i++)
  1181.         {
  1182.         if (!(board[i] == bd[i] && color[i] == cl[i]))
  1183.           {
  1184.               go = false;
  1185.               break;
  1186.           }
  1187.         }
  1188.       if (go)
  1189.         {
  1190.         m = 0x3424;
  1191.  
  1192.         /*
  1193.              * make sure the move is in the MoveList
  1194.              */
  1195.         for (pnt = TrPnt[1]; pnt < TrPnt[2]; pnt++)
  1196.           {
  1197.               if (((Tree[pnt].f << 8) | Tree[pnt].t) == (short) m)
  1198.             {
  1199.                 Tree[pnt].flags |= book;
  1200.                 Tree[pnt].score = 0;
  1201.                 break;
  1202.             }
  1203.           }
  1204.         /* Make sure its the best */
  1205.  
  1206.         pick (TrPnt[1], TrPnt[2] - 1);
  1207.         if (!Tree[TrPnt[1]].score)
  1208.           {
  1209.               /* ok pick up the hint and go */
  1210.               *hint = 0x0112;
  1211.               return true;
  1212.           }
  1213.         }
  1214.       }
  1215. #endif
  1216.     gsrand ((unsigned int) time ((long *) 0));
  1217.     m = 0;
  1218.     cnt = 0;
  1219.     tcnt = 0;
  1220.     ccnt = 0;
  1221.     OC = NULL;
  1222.  
  1223.  
  1224.     /*
  1225.      * find all the moves for this position  - count them and get their
  1226.      * total count
  1227.      */
  1228.     OB = BookTable[hashkey & BOOKMASK];
  1229.     while (OB->count)
  1230.       {
  1231.       if (OB->bookkey == hashkey
  1232.           && OB->bookbd == hashbd
  1233.           && ((OB->flags) & SIDEMASK) == side)
  1234.         {
  1235.         if (OB->bmove & BADMOVE)
  1236.           {
  1237.               m = OB->bmove ^ BADMOVE;
  1238.               /* is the move is in the MoveList */
  1239.               for (pnt = TrPnt[1]; pnt < TrPnt[2]; pnt++)
  1240.             {
  1241.                 if (((Tree[pnt].f << 8) | Tree[pnt].t) == m)
  1242.                   {
  1243.                   if (--possibles)
  1244.                     {
  1245.                     Tree[pnt].score = DONTUSE;
  1246.                     break;
  1247.                     }
  1248.                   }
  1249.             }
  1250.  
  1251.           }
  1252.         else
  1253.           {
  1254.               OC = OB;
  1255.               cnt++;
  1256.               tcnt += OB->count;
  1257.           }
  1258.         }
  1259.       if (++OB == OBEND)
  1260.           OB = OpenBook;
  1261.       }
  1262.     /* if only one just do it */
  1263.     if (cnt == 1)
  1264.       {
  1265.       m = OC->bmove;
  1266.       }
  1267.     else
  1268.     /* more than one must choose one at random */
  1269.     if (cnt > 1)
  1270.       {
  1271.       /* pick a number */
  1272.       r = urand () % 1000;
  1273.  
  1274.       OC = BookTable[hashkey & BOOKMASK];
  1275.       while (OC->count)
  1276.         {
  1277.         if (OC == OBEND)
  1278.             OC = OpenBook;
  1279.         if (OC->bookkey == hashkey
  1280.             && OC->bookbd == hashbd
  1281.             && ((OC->flags) & SIDEMASK) == side
  1282.             && !(OC->bmove & BADMOVE))
  1283.           {
  1284.               ccnt += OC->count;
  1285.                       if ((((unsigned long) ccnt * BOOKRAND) / tcnt) >= r)
  1286.             {
  1287.                 m = OC->bmove;
  1288.                 break;
  1289.             }
  1290.           }
  1291.         if (++OC == OBEND)
  1292.             OC = OpenBook;
  1293.         }
  1294.       }
  1295.     else
  1296.       {
  1297.       /* none decrement count of no finds */
  1298.       Book--;
  1299.       return false;
  1300.       }
  1301.     /* make sure the move is in the MoveList */
  1302.     for (pnt = TrPnt[1]; pnt < TrPnt[2]; pnt++)
  1303.       {
  1304.       if (((Tree[pnt].f << 8) | Tree[pnt].t) == m)
  1305.         {
  1306.         Tree[pnt].flags |= book;
  1307.         Tree[pnt].score = 0;
  1308.         break;
  1309.         }
  1310.       }
  1311.     /* Make sure its the best */
  1312.  
  1313.     pick (TrPnt[1], TrPnt[2] - 1);
  1314.     if (Tree[TrPnt[1]].score)
  1315.       {
  1316.       /* no! */
  1317.       Book--;
  1318.       return false;
  1319.       }
  1320.     /* ok pick up the hint and go */
  1321.     *hint = OC->hint;
  1322.     return true;
  1323. }
  1324.  
  1325. #endif
  1326.